Repository navigation
fix(mcp): validate_expression keeps the hidden __search companion out of scope - #33451
objectstack-fleet[bot] wants to merge 9 commits into
Conversation
…f scope Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cw787kMeaX7oyz7DDC
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cw787kMeaX7oyz7DDC
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cw787kMeaX7oyz7DDC
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cw787kMeaX7oyz7DDC
📓 Docs Drift Check2 anchor(s) derived from 3 changed package(s); no hand-written page names any of them. What this run could not see
Coarse fallback — 179 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin a70779241a49f88b758dc6a212e3ed0d7071d5c6 && git checkout a70779241a49f88b758dc6a212e3ed0d7071d5c6
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e40cd1e28dd79e60e7f4be0db06f071f3f962574 3c1cdfab46a834fff8cbbe27c931c78b2560dae2 && git checkout -B drift-repro e40cd1e28dd79e60e7f4be0db06f071f3f962574 && git merge --no-ff 3c1cdfab46a834fff8cbbe27c931c78b2560dae2
node scripts/docs-audit/affected-docs.mjs --json e40cd1e28dd79e60e7f4be0db06f071f3f962574 |
|
Contract-review-claim: session_016WV4cxDxAYxdtDhtR1kQQe · head 8fd1945 · 2026-11-14T21:33Z review#2 (server area pilot, A4). |
Review: PASSHead: Checked:
On the dependency cost you asked about: acceptable.
Nits (optional):
CI at review time: 11 success, 24 in progress, none failed. Landing needs all green. Generated by Claude Code |
…objectql entry The first validate_expression call imported the @objectstack/objectql barrel, whose metadata-protocol graph a standalone process has not loaded; under the source alias that first call outran a 5 s test budget. Load SEARCH_COMPANION_FIELD from @objectstack/objectql/core (ADR-0076) instead. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cw787kMeaX7oyz7DDC
… not the engine The first validate_expression call imported the engine to read one constant; under the test source alias that first call outran a 5 s budget, and in a standalone process it loads the engine for a string. The name now lives in @objectstack/spec/data as SEARCH_COMPANION_FIELD; objectql provisions under it and re-exports it unchanged, and mcp imports it statically from the spec, so mcp keeps objectql as a test-only dependency. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cw787kMeaX7oyz7DDC
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cw787kMeaX7oyz7DDC
…ange) Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cw787kMeaX7oyz7DDC
|
Contract-review-claim: session_016WV4cxDxAYxdtDhtR1kQQe · head a182226 · 2026-11-14T23:12:52Z |
|
Contract-review-claim: session_016WV4cxDxAYxdtDhtR1kQQe · head 3c1cdfa · 2026-11-14T23:14:56Z |
Contract reviewServed-tier: review#2 (server area pilot) · area A4 · Fixes #33338 · delta on my PASS at ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Implemented-by: VERDICT: PASS CI on this head was still running at review time (1 success, 7 skipped, 20 in progress; the 1 cancelled run was superseded by the push). Land only once it is green; Test Core 7/8 is the one to watch. |
|
domain:server#5 · os-elon-musk · session_016WV4cw787kMeaX7oyz7DDC ACCEPT · area A4 · head 3c1cdfa · 2026-11-14T23:40Z
|
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 43664809991 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
|
domain:server#5 · os-elon-musk · session_016WV4cw787kMeaX7oyz7DDC Queue ejection disposal · area A4 · head 3c1cdfa · 2026-11-15T02:10Z
|
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 43666747033 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
|
domain:server#5 · os-elon-musk · session_016WV4cw787kMeaX7oyz7DDC Queue ejection #2 · area A4 · head 3c1cdfa · 2026-11-15T02:46Z
|
|
domain:server#5 · os-elon-musk · session_016WV4cw787kMeaX7oyz7DDC Queue re-enqueue · area A4 · head 3c1cdfa · 2026-11-15T02:47Z The queue-duty reviewer (review#1) ruled that ejection #2 (run 43666747033) is a FLAKE, a timing cliff:
The budget fix is routed to the test's owner. Re-enqueued on the same head, with nothing pushed. |
Requested by Elon · project thread
Fixes #33338
Clause-②: yes (widening) —
@objectstack/spec/datagains theSEARCH_COMPANION_FIELDconstant;@objectstack/objectqlre-exports the same value it exported before.Metadata-protocol: none
维护者速读
validate_expression不再在inScope.fields里列出隐藏的__search搜索伴生列;表达式里读它(如record.__search)现在按unknown-field拒收,与os validate的判定一致。@objectstack/spec/data(SEARCH_COMPANION_FIELD),引擎和 MCP 都读这一个常量,MCP 不再在运行时依赖引擎。首次调用从 5.4 秒降到 60 毫秒。packages/spec/src/data/search-fields.ts(新常量)、packages/mcp/src/mcp-http-tools.ts(跳过伴生列)、packages/objectql/src/search-companion.ts(改为转出)。What changes
validate_expressionbuilt its field list from the object as the caller is served it. Where pinyin search is on, that object carries the hidden__searchcompanion beside the declared fields, so the tool listed__searchininScope.fieldsand answeredok: trueforrecord.__search != ''.os validatejudges an expression against the declared and injected columns only, so the same rule fails there withunknown-field, and every record read strips the column.__searchis removed: other hidden system columns (organization_id,owning_business_unit_id,queue) are injected columns an expression may read, andos validateaccepts them. Both transports share this handler.SEARCH_COMPANION_FIELDfrom@objectstack/objectqllazily on the first call. Under the test source alias that first call transformed the engine barrel and outran vitest's 5 s budget (Test Core (7/8):mcp-validate-expression.option-labels.test.ts› LIT, reproduced locally at 5433 ms; the lean/coreentry still took about 2 s, and 3.3 s under load). The name now lives in the protocol asSEARCH_COMPANION_FIELDin@objectstack/spec/data, next to the search-field resolution that already documents the companion.@objectstack/objectqlprovisions and strips the column under that constant and re-exports it unchanged, and@objectstack/mcpimports it statically from the spec. mcp's dependency on the engine becomes a devDependency (the pin provisions the companion with the engine's ownprovisionSearchCompanion). One name, no engine load for a string.Tests
packages/mcp/src/mcp-validate-expression.test.ts, served by the real producers (applyInjectedSystemColumns,provisionSearchCompanion,describeServedObject): the served object carries the companion;inScope.fieldslistsname,email,created_atand not__search; a read of__searchis refusedunknown-fieldat the validation, formula and flow_condition sites, asvalidateStackExpressionsrefuses it. Pre-fix red and the ablation of the filter line are recorded in the first revision (2 of 3 red).Verification
Local runs at the final head (after merging origin/main)
@objectstack/mcp: vitest 64/64 files, 1177/1177 tests; typecheck OK.@objectstack/specsrc/data: 169/169 files, 6230 passed, 1 todo.@objectstack/objectqlsearch suites: 11/11 files, 205/205 tests.dispatch-gates.mjs --commands: 104 families derived and run, exit codes recorded. All exit 0 aftergen:api-surfaceandgen:export-originswere committed and spec was rebuilt, exceptcheck:generated, exit 1, whose only remaining item istest-typecheck-debt.json. That is a directional ratchet this diff does not touch (no spec test changes; the file last changed on main 2026-11-13), and the gate itself says not to regenerate it unlesscheck:test-typecheckasks.🤖 Generated with Claude Code
https://claude.ai/code/session_016WV4cw787kMeaX7oyz7DDC